from __future__ import absolute_import, division

from gui.panda.base import *


class Picker(Object):
    control   = Attribute()
    mouse     = Attribute()
    scene     = Attribute()
    display   = Attribute()
    
    is_occluded = Attribute(initial = False, writable = True)
    
    picking_queue     = Attribute()
    picking_traverser = Attribute()
    picking_ray       = Attribute()
    
    last_pointer = Attribute(initiable = False, writable = True)
    last_point   = Attribute(initiable = False, writable = True)
    
    def setup(self):
        self.picking_queue     = CollisionHandlerQueue()
        self.picking_traverser = CollisionTraverser('picking')
        self.picking_ray       = CollisionRay()        
        
        node = CollisionNode('picking')
        node.setFromCollideMask(GeomNode.getDefaultCollideMask())
        node.addSolid(self.picking_ray)
        
        path = self.camera.attachNewNode(node)
        
        self.picking_traverser.addCollider(path, self.picking_queue)
    
    @property
    def camera(self):
        return self.display.getCamera()
    
    def update(self):
        if not self.mouse.hasMouse():
            return
        
        pointer  = self.mouse.getMouse()
        position = (pointer.getX(), pointer.getY())
        
        self.is_occluded = self.control.is_occluded(Position(pointer.getX(), pointer.getY()))

        if self.last_pointer == position:
            return
        
        self.last_pointer = position
        self.last_point   = None
        
        self.picking_ray.setFromLens(self.camera.node(), pointer.getX(), pointer.getY())
        self.picking_traverser.traverse(render)
        self.picking_queue.sortEntries()
    
    @property
    def point(self):
        if self.last_point is not None and not self.is_occluded:
            return self.last_point
        elif self.is_occluded or self.picking_queue.getNumEntries() == 0:
            return None
        else:
            self.last_point = self.picking_queue.getEntry(0).getSurfacePoint(self.scene)
            
            return self.last_point
    
    @property
    def vector(self):
        point = self.point
        
        if self.point is None:
            return Vec4(-1, -1, 0, 0)
        else:
            return Vec4(point.getX(), point.getY(), 0, 0)
